package org.opens.netty.chatServer.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;

/**
 * 功能描述
 *
 * @author: zhangyuming
 * @date: 2024/3/20 15:09
 */
@Slf4j
@Data
public class TcpClient {

    public static final int RECONNECT_INTERVAL_SECONDS = 5;

    private SocketChannel channel;

    private final NioEventLoopGroup bossEventLoopGroup;

    private String remoteIp;

    private int remotePort;

    public TcpClient(String remoteIp, int remotePort) {
        this.remoteIp = remoteIp;
        this.remotePort = remotePort;
        this.bossEventLoopGroup = new NioEventLoopGroup();
    }

    public void start() {
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.channel(NioSocketChannel.class);
            bootstrap.group(this.bossEventLoopGroup);
            bootstrap.remoteAddress(this.remoteIp, this.remotePort);
            bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
            bootstrap.option(ChannelOption.TCP_NODELAY, true);
            bootstrap.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                        @Override
                        public void channelActive(ChannelHandlerContext ctx) throws Exception {

                        }

                        @Override
                        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                            ByteBuf byteBuf = (ByteBuf) msg;
                            String hexString = ByteBufUtil.hexDump(byteBuf);
                            log.info("收到数据：{}", hexString);
                            super.channelRead(ctx, msg);
                        }
                    });
                }
            });
            connect(bootstrap);
        } catch (Exception e) {
            log.error("client error: ", e);
        }
    }

    private void connect(Bootstrap bootstrap) {
        bootstrap.connect().addListener((ChannelFuture future) -> {
            if (future.isSuccess()) {
                log.info("TCP CLIENT启动成功！");
                channel = (SocketChannel) future.channel();
                channel.closeFuture().addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        // 优雅的停下来-停止接受新任务, 等待把未发送的数据发完之后再将group中的EventLoop线程关闭, 不是立刻停止
                        bossEventLoopGroup.shutdownGracefully();
                        log.info("连接已关闭");
                    }
                });
            } else {
                log.warn("TCP CLIENT连接失败，将在 {} 秒后尝试重连...", RECONNECT_INTERVAL_SECONDS);
                future.channel().eventLoop().schedule(() -> connect(bootstrap), RECONNECT_INTERVAL_SECONDS, TimeUnit.SECONDS);
            }
        });
    }

    private void close() {
        if (this.channel != null) {
            this.channel.close();
        }
        //this.bossEventLoopGroup.shutdownGracefully();
    }

    public static void main(String[] args) {
        TcpClient tcpClient = new TcpClient("127.0.0.1", 5005);
        tcpClient.start();
    }

}
